import { extendClassProps, react, reactJson, reactPositions, UniteChanged } from "xbsj-base";
import { ESVisualObject } from "./ESVisualObject";
import { BooleanProperty, ESJFillStyle, ESJPointStyle, ESJStrokeStyle, ESJVector2D, ESJVector3D, ESJVector3DArray, FunctionProperty, GroupProperty, JsonProperty } from "@/ESJTypes";
import { geoArea, geoBuffer, geoDifference, geoIntersect, geoPolygonOverlap, geoUnion, getDistancesFromPositions } from "@/utils";
export abstract class ESGeoVector extends ESVisualObject {

    private _editing = this.dv(react<boolean>(false));
    get editing() { return this._editing.value; }
    set editing(value: boolean) { this._editing.value = value; }
    get editingChanged() { return this._editing.changed; }

    constructor(id?: string) { super(id); }

    getArea() {
        if (this.points && this.points.length >= 3) {
            return geoArea(this.points)
        } else {
            return undefined
        }
    }

    getDistance() {
        if (this.points && this.points.length >= 2) {
            const distances = getDistancesFromPositions(this.points, 'NONE');
            return distances[distances.length - 1];
        } else {
            return undefined
        }
    }
    getPerimeter() {
        if (this.points && this.points.length >= 3) {
            const pos = [...this.points, this.points[0]];
            const distances = getDistancesFromPositions(pos, 'NONE');
            return distances[distances.length - 1];
        } else {
            return undefined
        }
    }

    //交集计算
    getIntersect(position: ESJVector3DArray) {
        if (this.points && this.points.length >= 3 && position.length >= 3) {
            const pos = geoIntersect(this.points, position)
            if (!pos) return undefined;
            const e1 = pos[0][0][0]
            if (Array.isArray(e1)) {
                const p1 = [...pos] as ESJVector2D[][][]
                const list: ESJVector3DArray[] = []
                p1.forEach(el => {
                    const arr = el[0].map(ex => [...ex, 0] as ESJVector3D)
                    list.push(arr)
                })
                return list
            } else {
                const p2 = [...pos] as ESJVector2D[][]
                const p3 = p2[0].map(e => [...e, 0] as ESJVector3D)
                return [p3]
            }
        } else {
            return undefined
        }
    }
    //并集计算
    getUnion(position: ESJVector3DArray) {
        if (this.points && this.points.length >= 3 && position.length >= 3) {
            const pos = geoUnion(this.points, position)
            if (!pos) return undefined;
            const e1 = pos[0][0][0]
            if (Array.isArray(e1)) {
                const p1 = [...pos] as ESJVector2D[][][]
                const list: ESJVector3DArray[] = []
                p1.forEach(el => {
                    const arr = el[0].map(ex => [...ex, 0] as ESJVector3D)
                    list.push(arr)
                })
                return list
            } else {
                const p2 = [...pos] as ESJVector2D[][]
                const p3 = p2[0].map(e => [...e, 0] as ESJVector3D)
                return [p3]
            }
        } else {
            return undefined
        }
    }

    /**
     * 裁切
     * @param positions 用来裁切多边形的多边形
     * @returns 如果返回对象自身的positions,表示用来裁切的多边形完全包含在对象多边形之中，裁切出来中空的多边形需要自行处理；
     * 其他情况正常返回多边形值。
     */
    getDifference(position: ESJVector3DArray) {
        if (this.points && this.points.length >= 3 && position.length >= 3) {
            const pos = geoDifference(this.points, position)
            if (!pos) return undefined;
            const e1 = pos[0][0][0]
            if (Array.isArray(e1)) {
                const p1 = [...pos] as ESJVector2D[][][]
                const list: ESJVector3DArray[] = []
                p1.forEach(el => {
                    const arr = el[0].map(ex => [...ex, 0] as ESJVector3D)
                    list.push(arr)
                })
                return list
            } else {
                const p2 = [...pos] as ESJVector2D[][]
                const p3 = p2[0].map(e => [...e, 0] as ESJVector3D)
                return [p3]
            }
        } else {
            return undefined
        }
    }
    //缓冲计算
    getBuffer(radius: number = 500, units?: string) {
        if (this.points && this.points.length >= 2) {
            const pos = geoBuffer(this.points, radius, units)
            if (!pos) return undefined;
            return [pos[0].map((e: ESJVector2D) => [...e, 0] as ESJVector3D)]
        } else {
            return undefined
        }
    }
    //计算是否一个多边形在另一个多边形内部
    geoPolygonOverlap(position: ESJVector3DArray) {
        if (this.points && this.points.length >= 3 && position.length >= 3) {
            const pos = geoPolygonOverlap(this.points, position);
            if (pos === "oneBig") {
                return true;
            } else if (pos === "twoBig") {
                return false;
            } else {
                return undefined;
            }
        } else {
            return undefined
        }
    }

    static override defaults = {
        ...ESVisualObject.defaults,
        points: [] as ESJVector3DArray,
        pointStyle: {
            size: 1,
            sizeType: 'screen',
            color: [1, 1, 1, 1],
            material: '',
            materialParams: {}
        } as ESJPointStyle,
        strokeStyle: {
            width: 1,
            widthType: 'screen',
            color: [1, 1, 1, 1],
            material: '',
            materialParams: {},
            ground: false
        } as ESJStrokeStyle,
        fillStyle: {
            color: [1, 1, 1, 1],
            material: '',
            materialParams: {},
            ground: false
        } as ESJFillStyle,
        pointed: false,
        stroked: false,
        filled: false
    };

    override getESProperties() {
        const properties = { ...super.getESProperties() };
        return {
            ...properties,
            coordinate: [
                ...properties.coordinate,
                new BooleanProperty('编辑', '编辑', false, false, [this, 'editing'], false),
                new JsonProperty('位置数组', '位置数组(经纬高数组)', true, false, [this, 'points'], ESGeoVector.defaults.points),
            ],
            style: [
                ...properties.style,
                new BooleanProperty('开启点样式', '开启点样式', false, false, [this, 'pointed'], false),
                new BooleanProperty('开启线样式', '开启线样式', false, false, [this, 'stroked'], false),
                new BooleanProperty('开启填充样式', '开启填充样式', false, false, [this, 'filled'], false),
                new JsonProperty('点样式', '点样式(pointMaterialParams)', false, false, [this, 'pointStyle']),
                new JsonProperty('线样式', '线样式(strokeMaterialParams)', false, false, [this, 'strokeStyle']),
                new JsonProperty('填充样式', '填充样式(fillMaterialParams)', false, false, [this, 'fillStyle']),

            ],
        };
    };

    override getProperties(language?: string) {
        return [
            ...super.getProperties(language),
            new GroupProperty('ESGeoVector', 'ESGeoVector', [
                new BooleanProperty('是否编辑', '是否编辑', false, false, [this, 'editing']),
                new JsonProperty('位置数组', '位置数组(经纬高数组)', false, false, [this, 'points']),

                new BooleanProperty('开启点样式', '开启点样式', false, false, [this, 'pointed'], false),
                new BooleanProperty('开启线样式', '开启线样式', false, false, [this, 'stroked'], false),
                new BooleanProperty('开启填充样式', '开启填充样式', false, false, [this, 'filled'], false),
                new JsonProperty('点样式', '点样式(pointMaterialParams)', false, false, [this, 'pointStyle']),
                new JsonProperty('线样式', '线样式(strokeMaterialParams)', false, false, [this, 'strokeStyle']),
                new JsonProperty('填充样式', '填充样式(fillMaterialParams)', false, false, [this, 'fillStyle']),
            ]),
        ];
    }
}

export namespace ESGeoVector {
    export const createDefaultProps = () => ({
        ...ESVisualObject.createDefaultProps(),
        pointed: false,
        pointStyle: reactJson<ESJPointStyle>(ESGeoVector.defaults.pointStyle),
        stroked: false,
        strokeStyle: reactJson<ESJStrokeStyle>(ESGeoVector.defaults.strokeStyle),
        filled: false,
        fillStyle: reactJson<ESJFillStyle>(ESGeoVector.defaults.fillStyle),
        points: reactPositions(undefined),
    });
}
extendClassProps(ESGeoVector.prototype, ESGeoVector.createDefaultProps);
export interface ESGeoVector extends UniteChanged<ReturnType<typeof ESGeoVector.createDefaultProps>> { }
